package edu.cmu.mism.dgjava.utils;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.TreeEditor;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.forms.FormColors;

/**
 * This utility class provides convenience methods in creating controls on
 * preference pages.
 * 
 * @author Christian
 */
public class SWTUtils {
	// Defaults of controls
	public static final int DEFAULT_BUTTON_WIDTH = 70;
	public static final int DEFAULT_COMBO_WIDTH = 100;
	public static final int DEFAULT_CCOMBO_WIDTH = 100;
	public static final int DEFAULT_TEXTBOX_WIDTH = 100;
	public static final int DEFAULT_TREE_HEIGHT_WIDTH = 150;
	public static final int DEFAULT_COLUMN_WIDTH = 50;
	public static final int DEFAULT_RADIO_FILL = GridData.HORIZONTAL_ALIGN_BEGINNING
			| GridData.VERTICAL_ALIGN_CENTER;

	/**
	 * Creates a new checkbox and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the checkbox
	 * @return the new checkbox
	 */
	public static Button createCheckBox(Composite parent) {
		return createCheckBox(parent, null, 1, 0);
	}

	/**
	 * Creates a new checkbox and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the checkbox
	 * @param label
	 *            the string to set into the checkbox
	 * @param hSpan
	 *            the number of columns the new checkbox is to occupy
	 * @return the new checkbox
	 */
	public static Button createCheckBox(Composite parent, String label,
			int hSpan) {
		return createCheckBox(parent, label, hSpan, 0);
	}

	/**
	 * Creates a new checkbox and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the checkbox
	 * @param label
	 *            the string to set into the checkbox
	 * @param hSpan
	 *            the number of columns the new checkbox is to occupy
	 * @param indent
	 *            the number of pixels to indent from the left
	 * @return the new checkbox
	 */
	public static Button createCheckBox(Composite parent, String label,
			int hSpan, int indent) {
		Button button = new Button(parent, SWT.CHECK | SWT.LEFT);
		if (label == null) {
			button.setAlignment(SWT.CENTER);
		}
		GridData data = new GridData(GridData.FILL);
		data.horizontalSpan = hSpan;
		data.horizontalIndent = indent;
		button.setLayoutData(data);
		if (label != null) {
			button.setText(label);
		}
		button.setBackground(parent.getBackground());

		return button;
	}

	/**
	 * Creates a combo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @return the new combo box
	 */
	public static Combo createCombo(Composite parent, String[] items, int hSpan) {
		return createCombo(parent, items, hSpan, DEFAULT_COMBO_WIDTH);
	}

	/**
	 * Creates a combo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param tokenString
	 *            a tokenized string that will be split into the fields.
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @return the new combo box
	 */
	public static Combo createCombo(Composite parent, String tokenString,
			int hSpan) {
		return createCombo(parent, getTokenNames(tokenString), hSpan,
				DEFAULT_COMBO_WIDTH);
	}

	/**
	 * Creates a combo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param tokenString
	 *            a tokenized string that will be split into the fields.
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @return the new combo box
	 */
	public static Combo createCombo(Composite parent, String tokenString,
			int hSpan, int minWidth) {
		return createCombo(parent, getTokenNames(tokenString), hSpan, minWidth);
	}

	/**
	 * Creates a combo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @return the new combo box
	 */
	public static Combo createCombo(Composite parent, String[] items,
			int hSpan, int minWidth) {
		return createCombo(parent, items, hSpan, minWidth, false);
	}

	/**
	 * Creates a combo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @param bEditable
	 *            whether the items in the combo is editable
	 * @return the new combo box
	 */
	public static Combo createCombo(Composite parent, String tokenString,
			int hSpan, int minWidth, boolean bEditable) {
		return createCombo(parent, getTokenNames(tokenString), hSpan, minWidth,
				bEditable);
	}

	/**
	 * Creates a combo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @param bEditable
	 *            whether the items in the combo is editable
	 * @return the new combo box
	 */
	public static Combo createCombo(Composite parent, String[] items,
			int hSpan, int minWidth, boolean bEditable) {
		if (bEditable) {
			return createCombo(parent, items, hSpan, minWidth, bEditable,
					GridData.FILL_HORIZONTAL);
		}
		return createCombo(parent, items, hSpan, minWidth, bEditable,
				GridData.FILL);
	}

	/**
	 * Creates a combo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @param bEditable
	 *            whether the items in the combo is editable
	 * @param the
	 *            style to use on the GridData.
	 * @return the new combo box
	 */
	public static Combo createCombo(Composite parent, String[] items,
			int hSpan, int minWidth, boolean bEditable, int gridDataStyle) {
		return createCombo(parent, items, null, hSpan, minWidth, bEditable,
				gridDataStyle);
	}

	/**
	 * Creates a combo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param tooltipText
	 *            tooltip to be associated with this combo.
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @param bEditable
	 *            whether the items in the combo is editable
	 * @param the
	 *            style to use on the GridData.
	 * @return the new combo box
	 */
	public static Combo createCombo(Composite parent, String[] items,
			String tooltipText, int hSpan, int minWidth, boolean bEditable,
			int gridDataStyle) {
		Combo combo;
		GridData data;
		if (bEditable) {
			combo = new Combo(parent, SWT.DROP_DOWN);
			data = new GridData(gridDataStyle);
		} else {
			combo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY);
			data = new GridData(gridDataStyle);
		}
		data.horizontalSpan = hSpan;
		data.widthHint = minWidth;
		combo.setLayoutData(data);
		combo.setItems(items);
		if (tooltipText != null && tooltipText.length() > 0) {
			combo.setToolTipText(tooltipText);
		}
		return combo;
	}

	/**
	 * Creates a ccombo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @return the new combo box
	 */
	public static CCombo createCCombo(Composite parent, String[] items,
			int hSpan) {
		return createCCombo(parent, items, hSpan, DEFAULT_COMBO_WIDTH);
	}

	/**
	 * Creates a ccombo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param tokenString
	 *            a tokenized string that will be split into the fields.
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @return the new combo box
	 */
	public static CCombo createCCombo(Composite parent, String tokenString,
			int hSpan) {
		return createCCombo(parent, getTokenNames(tokenString), hSpan,
				DEFAULT_COMBO_WIDTH);
	}

	/**
	 * Creates a ccombo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param tokenString
	 *            a tokenized string that will be split into the fields.
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @return the new combo box
	 */
	public static CCombo createCCombo(Composite parent, String tokenString,
			int hSpan, int minWidth) {
		return createCCombo(parent, getTokenNames(tokenString), hSpan, minWidth);
	}

	/**
	 * Creates a ccombo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @return the new combo box
	 */
	public static CCombo createCCombo(Composite parent, String[] items,
			int hSpan, int minWidth) {
		return createCCombo(parent, items, hSpan, minWidth, false);
	}

	/**
	 * Creates a ccombo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @param bEditable
	 *            whether the items in the combo is editable
	 * @return the new combo box
	 */
	public static CCombo createCCombo(Composite parent, String tokenString,
			int hSpan, int minWidth, boolean bEditable) {
		return createCCombo(parent, getTokenNames(tokenString), hSpan,
				minWidth, bEditable);
	}

	/**
	 * Creates a ccombo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @param bEditable
	 *            whether the items in the combo is editable
	 * @return the new combo box
	 */
	public static CCombo createCCombo(Composite parent, String[] items,
			int hSpan, int minWidth, boolean bEditable) {
		if (bEditable) {
			return createCCombo(parent, items, hSpan, minWidth, bEditable,
					GridData.FILL_HORIZONTAL);
		}
		return createCCombo(parent, items, hSpan, minWidth, bEditable,
				GridData.FILL);
	}

	/**
	 * Creates a ccombo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @param bEditable
	 *            whether the items in the combo is editable
	 * @param the
	 *            style to use on the GridData.
	 * @return the new combo box
	 */
	public static CCombo createCCombo(Composite parent, String[] items,
			int hSpan, int minWidth, boolean bEditable, int gridDataStyle) {
		return createCCombo(parent, items, null, hSpan, minWidth, bEditable,
				gridDataStyle);
	}

	/**
	 * Creates a ccombo box and sets the default layout data.
	 * 
	 * @param parent
	 *            the composite in which to create the combo
	 * @param items
	 *            the items in the combo
	 * @param tooltipText
	 *            tooltip to be associated with this combo.
	 * @param hSpan
	 *            the number of columns the new combo is to occupy
	 * @param minWidth
	 *            minimum width of combo box in pixels
	 * @param bEditable
	 *            whether the items in the combo is editable
	 * @param the
	 *            style to use on the GridData.
	 * @return the new combo box
	 */
	public static CCombo createCCombo(Composite parent, String[] items,
			String tooltipText, int hSpan, int minWidth, boolean bEditable,
			int gridDataStyle) {
		CCombo combo;
		GridData data;
		if (bEditable) {
			combo = new CCombo(parent, SWT.BORDER);
			data = new GridData(gridDataStyle);
		} else {
			combo = new CCombo(parent, SWT.BORDER | SWT.READ_ONLY);
			data = new GridData(gridDataStyle);
		}
		data.horizontalSpan = hSpan;
		data.widthHint = minWidth;
		combo.setLayoutData(data);
		combo.setItems(items);
		if (tooltipText != null && tooltipText.length() > 0) {
			combo.setToolTipText(tooltipText);
		}

		return combo;
	}

	/**
	 * Creates composite control and sets the default layout data.
	 * 
	 * @param parent
	 *            the parent of the new composite
	 * @param hSpan
	 *            the number of columns for the new composite
	 * @return the newly-created composite
	 */
	public static Composite createComposite(Composite parent, int hSpan) {
		return createComposite(parent, hSpan, -1, -1, GridData.FILL_HORIZONTAL,
				-1, -1, -1);
	}

	/**
	 * Creates composite control and sets the default layout data.
	 * 
	 * @param parent
	 *            the parent of the new composite
	 * @param numColumns
	 *            the number of columns for the new composite
	 * @param verticalSpacing
	 *            the spacing between rows.
	 * @param horizontalSpan
	 *            the span for this new composite over the original composite.
	 * @return the newly-created composite
	 */
	public static Composite createComposite(Composite parent, int numColumns,
			int verticalSpacing, int horizontalSpan) {
		return createComposite(parent, numColumns, verticalSpacing,
				horizontalSpan, GridData.FILL_HORIZONTAL, -1, -1, -1);
	}

	/**
	 * Creates composite control and sets the default layout data.
	 * 
	 * @param parent
	 *            the parent of the new composite
	 * @param numColumns
	 *            the number of columns for the new composite
	 * @param verticalSpacing
	 *            the spacing between rows.
	 * @param horizontalSpan
	 *            the span for this new composite over the original composite.
	 * @param gridDataFill
	 *            the fill to use for this composite.
	 * @return the newly-created composite
	 */
	public static Composite createComposite(Composite parent, int numColumns,
			int verticalSpacing, int horizontalSpan, int gridDataFill) {
		return createComposite(parent, numColumns, verticalSpacing,
				horizontalSpan, gridDataFill, -1, -1, -1);
	}

	/**
	 * Creates composite control and sets the default layout data.
	 * 
	 * @param parent
	 *            the parent of the new composite
	 * @param numColumns
	 *            the number of columns for the new composite
	 * @param verticalSpacing
	 *            the spacing between rows.
	 * @param horizontalSpan
	 *            the horizontal span for this new composite over the original
	 *            composite.
	 * @param gridDataFill
	 *            the fill to use for this composite.
	 * @param horizontalSpacing
	 *            the spacing between objects.
	 * @param marginWidth
	 *            the spacing at start and end of composite.
	 * @param marginHeight
	 *            the spacing above and below composite.
	 * @return the newly-created composite
	 */
	public static Composite createComposite(Composite parent, int numColumns,
			int verticalSpacing, int horizontalSpan, int gridDataFill,
			int horizontalSpacing, int marginWidth, int marginHeight) {
		return createComposite(parent, numColumns, verticalSpacing,
				horizontalSpan, -1, gridDataFill, horizontalSpacing,
				marginWidth, marginHeight);
	}

	/**
	 * Creates composite control and sets the default layout data.
	 * 
	 * @param parent
	 *            the parent of the new composite
	 * @param numColumns
	 *            the number of columns for the new composite
	 * @param verticalSpacing
	 *            the spacing between rows.
	 * @param horizontalSpan
	 *            the horizontal span for this new composite over the original
	 *            composite.
	 * @param verticalSpan
	 *            the vertical span for this new composite over the original
	 *            composite.
	 * @param gridDataFill
	 *            the fill to use for this composite.
	 * @param horizontalSpacing
	 *            the spacing between objects.
	 * @param marginWidth
	 *            the spacing at start and end of composite.
	 * @param marginHeight
	 *            the spacing above and below composite.
	 * @return the newly-created composite
	 */
	public static Composite createComposite(Composite parent, int numColumns,
			int verticalSpacing, int horizontalSpan, int verticalSpan,
			int gridDataFill, int horizontalSpacing, int marginWidth,
			int marginHeight) {
		Composite composite = new Composite(parent, SWT.NONE);

		GridLayout layout = new GridLayout();
		layout.numColumns = numColumns;
		if (verticalSpacing >= 0) {
			layout.verticalSpacing = verticalSpacing;
		}
		if (horizontalSpacing >= 0) {
			layout.horizontalSpacing = horizontalSpacing;
		}
		if (marginWidth >= 0) {
			layout.marginWidth = marginWidth;
		}
		if (marginHeight >= 0) {
			layout.marginHeight = marginHeight;
		}
		composite.setLayout(layout);
		GridData gd = new GridData(gridDataFill);
		if (horizontalSpan > 0) {
			gd.horizontalSpan = horizontalSpan;
		}
		if (verticalSpan > 0) {
			gd.verticalSpan = verticalSpan;
		}
		composite.setLayoutData(gd);

		composite.setBackground(parent.getBackground());

		return composite;
	}

	/**
	 * Utility method that creates a group and sets the default layout data.
	 * 
	 * @param parent
	 *            the parent for the new group
	 * @param title
	 *            the label for the new group
	 * @param numColumns
	 *            the number of columns for the new group
	 * @return the newly created group
	 */
	public static Group createGroup(Composite parent, String title,
			int numColumns) {
		return createGroup(parent, title, numColumns, -1,
				GridData.FILL_HORIZONTAL);
	}

	/**
	 * Utility method that creates a group and sets the default layout data.
	 * 
	 * @param parent
	 *            the parent for the new group
	 * @param title
	 *            the label for the new group
	 * @param numColumns
	 *            the number of columns for the new group
	 * @param horizontalSpan
	 *            the number of columns this group should span on the parent
	 *            composite.
	 * @param fill
	 *            the fill style of the new group -- set to for filling just
	 *            around the object: GridData.BEGINNING | GridData.CENTER
	 * @return the newly created group
	 */
	public static Group createGroup(Composite parent, String title,
			int numColumns, int horizontalSpan, int gridDataFill) {
		return createGroup(parent, title, numColumns, horizontalSpan, -1,
				gridDataFill);
	}

	/**
	 * Utility method that creates a group and sets the default layout data.
	 * 
	 * @param parent
	 *            the parent for the new group
	 * @param title
	 *            the label for the new group
	 * @param numColumns
	 *            the number of columns for the new group
	 * @param horizontalSpan
	 *            the number of columns this group should span on the parent
	 *            composite.
	 * @param verticalSpan
	 *            the number of rows this group should span on the parent
	 *            composite.
	 * @param fill
	 *            the fill style of the new group -- set to for filling just
	 *            around the object: GridData.BEGINNING | GridData.CENTER
	 * @return the newly created group
	 */
	public static Group createGroup(Composite parent, String title,
			int numColumns, int horizontalSpan, int verticalSpan,
			int gridDataFill) {
		Group group = new Group(parent, SWT.SHADOW_ETCHED_IN);
		GridLayout layout = new GridLayout();
		layout.numColumns = numColumns;
		group.setLayout(layout);
		GridData data = new GridData(gridDataFill);

		if (horizontalSpan > 0) {
			data.horizontalSpan = horizontalSpan;
		}

		if (verticalSpan > 0) {
			data.verticalSpan = verticalSpan;
		}
		group.setLayoutData(data);
		group.setText(title);
		group.setBackground(parent.getBackground());

		return group;
	}

	/**
	 * Utility method that creates a group and sets the default layout data. *
	 * 
	 * @param parent
	 *            the parent of the new composite
	 * @param title
	 *            the label for the new group
	 * @param numColumns
	 *            the number of columns for the new composite
	 * @param horizontalSpan
	 *            the horizontal span for this new composite over the original
	 *            composite.
	 * @param verticalSpan
	 *            the vertical span for this new composite over the original
	 *            composite.
	 * @param gridDataFill
	 *            the fill to use for this composite.
	 * @param verticalSpacing
	 *            the spacing between rows.
	 * @param horizontalSpacing
	 *            the spacing between objects.
	 * @param marginWidth
	 *            the spacing at start and end of composite.
	 * @param marginHeight
	 *            the spacing above and below composite.
	 * @return the newly-created group
	 */
	public static Group createGroup(Composite parent, String title,
			int numColumns, int horizontalSpan, int verticalSpan,
			int gridDataFill, int horizontalSpacing, int verticalSpacing,
			int marginWidth, int marginHeight) {
		Group group = new Group(parent, SWT.SHADOW_ETCHED_IN);
		GridLayout layout = new GridLayout();
		layout.numColumns = numColumns;
		if (verticalSpacing >= 0) {
			layout.verticalSpacing = verticalSpacing;
		}
		if (horizontalSpacing >= 0) {
			layout.horizontalSpacing = horizontalSpacing;
		}
		if (marginWidth >= 0) {
			layout.marginWidth = marginWidth;
		}
		if (marginHeight >= 0) {
			layout.marginHeight = marginHeight;
		}
		group.setLayout(layout);
		GridData gd = new GridData(gridDataFill);
		if (horizontalSpan > 0) {
			gd.horizontalSpan = horizontalSpan;
		}
		if (verticalSpan > 0) {
			gd.verticalSpan = verticalSpan;
		}
		group.setLayoutData(gd);
		group.setText(title);
		group.setBackground(parent.getBackground());

		return group;
	}

	/**
	 * Utility method that creates a label instance and sets the default layout
	 * data.
	 * 
	 * @param parent
	 *            the parent for the new label
	 * @param text
	 *            the text for the new label
	 * @param hSpan
	 *            horizontal span of the new composite
	 * @return the new label
	 */
	public static Label createLabel(Composite parent, String text, int hSpan) {
		return createLabel(parent, text, hSpan, 1, 0, -1, -1);
	}

	/**
	 * Utility method that creates a label instance and sets the default layout
	 * data.
	 * 
	 * @param parent
	 *            the parent for the new label
	 * @param text
	 *            the text for the new label
	 * @param hSpan
	 *            the horizontal span of the new composite
	 * @param indent
	 *            number of pixels to indent from the left
	 * @return the new label
	 */
	public static Label createLabel(Composite parent, String text, int hSpan,
			int indent) {
		return createLabel(parent, text, hSpan, 1, indent, -1, -1);
	}

	/**
	 * Utility method that creates a label instance and sets the default layout
	 * data.
	 * 
	 * @param parent
	 *            the parent for the new label
	 * @param text
	 *            the text for the new label
	 * @param hSpan
	 *            the horizontal span of the new composite
	 * @param vSpan
	 *            the vertical span of the new composite
	 * @param indent
	 *            number of pixels to indent from the left
	 * @return the new label
	 */
	public static Label createLabel(Composite parent, String text, int hSpan,
			int vSpan, int indent) {
		return createLabel(parent, text, hSpan, vSpan, indent, -1, -1);
	}

	/**
	 * Utility method that creates a label instance and sets the default layout
	 * data.
	 * 
	 * @param parent
	 *            the parent for the new label
	 * @param text
	 *            the text for the new label
	 * @param hSpan
	 *            the horizontal span of the new composite
	 * @param vSpan
	 *            the vertical span of the new composite
	 * @param indent
	 *            number of pixels to indent from the left
	 * @param minWidth
	 *            non-negative to specify a starting width.
	 * @param minHeight
	 *            non-negative to specify a starting height.
	 * @return the new label
	 */
	public static Label createLabel(Composite parent, String text, int hSpan,
			int vSpan, int indent, int minWidth, int minHeight) {
		Label label = new Label(parent, SWT.LEFT);
		GridData data = new GridData();
		data.horizontalSpan = hSpan;
		data.horizontalAlignment = GridData.FILL;
		data.verticalSpan = vSpan;
		if (vSpan > 1) {
			data.verticalAlignment = GridData.BEGINNING;
		} else {
			data.verticalAlignment = GridData.CENTER;
		}
		data.horizontalIndent = indent;

		if (minWidth > 0) {
			data.widthHint = minWidth;
		}
		if (minHeight > 0) {
			data.heightHint = minHeight;
		}

		label.setLayoutData(data);
		label.setText(text);
		label.setBackground(parent.getBackground());

		return label;
	}

	/**
	 * Create an image label for sticking in a composite. The backgroud color is
	 * optional. Because images can have "transparent" natures, you might want
	 * to say the background is something other than the defaults composites
	 * background.
	 * 
	 * NOTE: the caller is responsible for cleanup of the image and color
	 * objects.
	 * 
	 * @param parent
	 *            the parent for the new label
	 * @param theImage
	 *            the image for the new label
	 * @param hSpan
	 *            the number of columns for the new composite
	 * @param background
	 *            pass null to use the composites background.
	 * @return the new label
	 */
	public static Label createLabelImage(Composite parent, Image theImage,
			int hSpan, Color background) {
		Label label = new Label(parent, SWT.LEFT);
		GridData data = new GridData();
		data.horizontalSpan = hSpan;
		data.horizontalAlignment = GridData.FILL;
		label.setLayoutData(data);
		if (background != null) {
			label.setBackground(background);
		}
		label.setImage(theImage);
		return label;
	}

	/**
	 * Utility method that creates a push button instance and sets the default
	 * layout data.
	 * 
	 * @param parent
	 *            the parent for the new button
	 * @param label
	 *            the label for the new button
	 * @return the newly-created button
	 */
	public static Button createPushButton(Composite parent, String label) {
		return createPushButton(parent, label, DEFAULT_BUTTON_WIDTH);
	}

	/**
	 * Utility method that creates a push button instance and sets the default
	 * layout data.
	 * 
	 * @param parent
	 *            the parent for the new button
	 * @param label
	 *            the label for the new button
	 * @param widthHint
	 *            use this width for the button.
	 * @return the newly-created button
	 */
	public static Button createPushButton(Composite parent, String label,
			int widthHint) {
		return createPushButton(parent, label, -1, widthHint);
	}

	/**
	 * Utility method that creates a push button instance and sets the default
	 * layout data.
	 * 
	 * @param parent
	 *            the parent for the new button.s
	 * @param label
	 *            the label for the new button.
	 * @param indent
	 *            the number of pixels to indent from the left.
	 * @param widthHint
	 *            use this width for the button.
	 * @return the newly-created button
	 */
	public static Button createPushButton(Composite parent, String label,
			int indent, int widthHint) {
		Button button = new Button(parent, SWT.PUSH);
		GridData data = new GridData();
		data.horizontalAlignment = GridData.FILL_HORIZONTAL;
		data.verticalAlignment = GridData.BEGINNING;
		if (indent > -1) {
			data.horizontalIndent = indent;
		}
		data.widthHint = widthHint;
		button.setLayoutData(data);
		button.setText(label);
		return button;
	}

	/**
	 * Utility method that creates a push button instance and sets the default
	 * layout data.
	 * 
	 * @param parent
	 *            the parent for the new button
	 * @param label
	 *            the label for the new button
	 * @param widthHint
	 *            use this width for the button.
	 * @return the newly-created button
	 */
	public static Button createPushButton(Composite parent, Image theImage,
			int widthHint) {
		Button button = new Button(parent, SWT.PUSH);
		GridData data = new GridData();
		data.horizontalAlignment = GridData.FILL_HORIZONTAL;
		data.widthHint = widthHint;
		button.setLayoutData(data);
		button.setImage(theImage);
		button.setAlignment(SWT.CENTER);
		return button;
	}

	/**
	 * Utility method that creates a toggle button instance and sets the default
	 * layout data.
	 * 
	 * @param parent
	 *            the parent for the new button
	 * @param label
	 *            the label for the new button
	 * @param widthHint
	 *            use this width for the button.
	 * @return the newly-created button
	 */
	public static Button createToggleButton(Composite parent, Image theImage,
			int widthHint) {
		Button button = new Button(parent, SWT.TOGGLE);
		GridData data = new GridData();
		data.horizontalAlignment = GridData.FILL_HORIZONTAL;
		data.widthHint = widthHint;
		button.setLayoutData(data);
		button.setImage(theImage);
		button.setAlignment(SWT.CENTER);
		return button;
	}

	/**
	 * Utility method that creates a radio button instance and sets the default
	 * layout data.
	 * 
	 * @param parent
	 *            the parent for the new button
	 * @param label
	 *            the label for the new button
	 * @return the newly-created button
	 */
	public static Button createRadioButton(Composite parent, String label) {
		return createRadioButton(parent, label, DEFAULT_RADIO_FILL);
	}

	/**
	 * Utility method that creates a radio button instance and sets the default
	 * layout data.
	 * 
	 * @param parent
	 *            the parent for the new button
	 * @param label
	 *            the label for the new button
	 * @return the newly-created button
	 */
	public static Button createRadioButton(Composite parent, String label,
			int gridDataFill) {
		return createRadioButton(parent, label, gridDataFill, 1);
	}

	/**
	 * Utility method that creates a radio button instance and sets the default
	 * layout data.
	 * 
	 * @param parent
	 *            the parent for the new button
	 * @param label
	 *            the label for the new button
	 * @param horizontalSpan
	 *            number of columns occupied by button
	 * @return the newly-created button
	 */
	public static Button createRadioButton(Composite parent, String label,
			int gridDataFill, int horizontalSpan) {
		Button button = new Button(parent, SWT.RADIO | SWT.LEFT);
		GridData data = new GridData(gridDataFill);
		data.horizontalSpan = horizontalSpan;
		button.setLayoutData(data);
		button.setText(label);
		button.setBackground(parent.getBackground());
		return button;
	}

	/**
	 * Utility method that creates an empty line
	 * 
	 * @param parent
	 *            the parent for the new label
	 * @param hSpan
	 *            the number of columns for the new composite
	 */
	public static void createSpacer(Composite parent, int hSpan) {
		createSpacer(parent, hSpan, 0);
	}

	/**
	 * Utility method that creates an empty line
	 * 
	 * @param parent
	 *            the parent for the new label
	 * @param hSpan
	 *            the number of columns for the new composite
	 * @param int minimum width of spacer
	 */
	public static void createSpacer(Composite parent, int hSpan, int minWidth) {
		Label label = new Label(parent, SWT.NONE);
		GridData data = new GridData();
		data.horizontalSpan = hSpan;
		data.widthHint = minWidth;
		label.setLayoutData(data);
		label.setBackground(parent.getBackground());
	}

	/**
	 * Create a separator that goes across the entire page
	 * 
	 * @param parent
	 *            the parent for the new label
	 * @param hSpan
	 *            the number of columns for the new composite
	 */
	public static void createSeparator(Composite parent, int hSpan) {
		Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
		GridData data = new GridData();
		data.horizontalSpan = hSpan;
		data.horizontalAlignment = GridData.FILL;
		data.grabExcessHorizontalSpace = true;
		separator.setLayoutData(data);
		separator.setBackground(parent.getBackground());
	}

	/**
	 * Create a table from a Composite object
	 * 
	 * @param composite
	 *            the Composite this table is to be created from
	 * @param tokenString
	 *            A string containing names of the columns in the order that
	 *            they should be displayed in the table with each column
	 *            separated by a comma(',') or null if no columns need to be
	 *            created.
	 * @param tableWidth
	 *            the minimum width for the table
	 * @param tableHeight
	 *            the minimum height for the table
	 * @return the new table
	 */
	public static Table createTable(Composite composite, String tokenString,
			int tableWidth, int tableHeight) {
		return createTable(composite, tokenString, tableWidth, tableHeight,
				false);
	}

	/**
	 * Create a table from a Composite object
	 * 
	 * @param composite
	 *            the Composite this table is to be created from
	 * @param tokenString
	 *            A string containing names of the columns in the order that
	 *            they should be displayed in the table with each column
	 *            separated by a comma(',') or null if no columns need to be
	 *            created.
	 * @param tableWidth
	 *            the minimum width for the table.
	 * @param tableHeight
	 *            the minimum height for the table.
	 * @param bMulti
	 *            Whether multiple selection is allowed.
	 * @return the new table
	 */
	public static Table createTable(Composite composite, String tokenString,
			int tableWidth, int tableHeight, boolean bMulti) {
		return createTable(composite, tokenString, tableWidth, tableHeight, 1,
				bMulti);
	}

	/**
	 * Create a table from a Composite object
	 * 
	 * @param composite
	 *            the Composite this table is to be created from
	 * @param tokenString
	 *            A string containing names of the columns in the order that
	 *            they should be displayed in the table with each column
	 *            separated by a comma(',') or null if no columns need to be
	 *            created.
	 * @param tableWidth
	 *            the minimum width for the table.
	 * @param tableHeight
	 *            the minimum height for the table.
	 * @param horizontalSpan
	 *            the number of columns the table is to occupy.
	 * @param bMulti
	 *            Whether multiple selection is allowed.
	 * @return the new table
	 */
	public static Table createTable(Composite composite, String tokenString,
			int tableWidth, int tableHeight, int horizontalSpan, boolean bMulti) {
		return createTable(composite, tokenString, tableWidth, tableHeight,
				horizontalSpan, bMulti, false);
	}

	/**
	 * Create a table from a Composite object
	 * 
	 * @param composite
	 *            the Composite this table is to be created from
	 * @param tokenString
	 *            A string containing names of the columns in the order that
	 *            they should be displayed in the table with each column
	 *            separated by a comma(',') or null if no columns need to be
	 *            created.
	 * @param tableWidth
	 *            the minimum width for the table.
	 * @param tableHeight
	 *            the minimum height for the table.
	 * @param horizontalSpan
	 *            the number of columns the table is to occupy.
	 * @param bMulti
	 *            Whether multiple selection is allowed.
	 * @param bCheck
	 *            Whether to display a checkbox in front of each table item.
	 * @return the new table
	 */
	public static Table createTable(Composite composite, String tokenString,
			int tableWidth, int tableHeight, int horizontalSpan,
			boolean bMulti, boolean bCheck) {
		return createTable(composite, tokenString, tableWidth, tableHeight,
				horizontalSpan, 1, bMulti, bCheck);
	}

	/**
	 * Create a table from a Composite object
	 * 
	 * @param composite
	 *            the Composite this table is to be created from
	 * @param tokenString
	 *            A string containing names of the columns in the order that
	 *            they should be displayed in the table with each column
	 *            separated by a comma(',') or null if no columns need to be
	 *            created.
	 * @param tableWidth
	 *            the minimum width for the table.
	 * @param tableHeight
	 *            the minimum height for the table.
	 * @param horizontalSpan
	 *            the number of columns the table is to occupy.
	 * @param verticalSpan
	 *            the number of rows the table is to occupy.
	 * @param bMulti
	 *            Whether multiple selection is allowed.
	 * @param bCheck
	 *            Whether to display a checkbox in front of each table item.
	 * @return the new table
	 */
	public static Table createTable(Composite composite, String tokenString,
			int tableWidth, int tableHeight, int horizontalSpan,
			int verticalSpan, boolean bMulti, boolean bCheck) {
		// SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION
		int style = SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER
				| SWT.FULL_SELECTION;
		style = style | (bMulti ? SWT.MULTI : SWT.SINGLE);
		style = bCheck ? (style | SWT.CHECK) : style;

		Table table = new Table(composite, style);
		GridData gridData = new GridData(GridData.FILL_BOTH);
		gridData.horizontalSpan = horizontalSpan;
		gridData.verticalSpan = verticalSpan;
		if (tableWidth > 0) {
			gridData.widthHint = tableWidth;
		}
		if (tableHeight > 0) {
			gridData.heightHint = tableHeight;
		}
		table.setLayoutData(gridData);
		table.setHeaderVisible(true);
		table.setLinesVisible(true);

		if (tokenString != null) {
			String[] columns = getTokenNames(tokenString);

			int columnSize = DEFAULT_COLUMN_WIDTH;
			if (tableWidth > 0) {
				columnSize = tableWidth / columns.length;
			}
			for (int ii = 0; ii < columns.length; ii++) {
				createTableColumn(table, columns[ii], ii, columnSize);
			}
		}

		return table;
	}

	/**
	 * Creates a TabFolder widget.
	 * 
	 * @param composite
	 *            the Composite this TabFolder is to be created from
	 * @param folderWidth
	 *            the width of each folder tab.
	 * @param folderHeight
	 *            the height of each folder tab.
	 * @param horizontalSpan
	 *            the number of columns the TabFolder is to occupy.
	 * @param verticalSpan
	 *            the number of rows the TabFolder is to occupy.
	 * @return
	 */
	public static TabFolder createTabFolder(Composite composite,
			int folderWidth, int folderHeight, int horizontalSpan,
			int verticalSpan) {
		// SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION
		int style = SWT.V_SCROLL | SWT.H_SCROLL;

		TabFolder folder = new TabFolder(composite, style);
		GridData gridData = new GridData(GridData.FILL_BOTH);
		gridData.horizontalSpan = horizontalSpan;
		gridData.verticalSpan = verticalSpan;
		if (folderWidth > 0) {
			gridData.widthHint = folderWidth;
		}
		if (folderHeight > 0) {
			gridData.heightHint = folderHeight;
		}
		folder.setLayoutData(gridData);

		return folder;
	}

	/**
	 * Create a table from a Composite object. The simple table is a simple
	 * version of the create table methods. This table doesn't have scroll bar
	 * settings or column headers. It should just a be a simple table.
	 * 
	 * @param composite
	 *            the Composite this table is to be created from
	 * @param tablewidth
	 *            the minimum width for the table
	 * @param bCheck
	 *            Whether to display a checkbox in front of each table item.
	 * @param bMulti
	 *            Whether multiple selection is allowed.
	 * @return the new table
	 */
	public static Table createSimpleTable(Composite composite, int tablewidth,
			boolean bCheck, boolean bMulti) {
		int style = SWT.BORDER | SWT.FULL_SELECTION;
		style = bCheck ? (style | SWT.CHECK) : style;
		style = style | (bMulti ? SWT.MULTI : SWT.SINGLE);

		Table table = new Table(composite, style);
		GridData gridData = new GridData(GridData.FILL_BOTH);
		gridData.widthHint = tablewidth;
		table.setLayoutData(gridData);
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
		return table;
	}

	/**
	 * Create a table column
	 * 
	 * @param parent
	 *            the table that contains this column
	 * @param name
	 *            name of this column
	 * @param index
	 *            the column within the parent composite
	 * @return the new table column
	 */
	public static TableColumn createTableColumn(Table parent, String name,
			int index) {
		return createTableColumn(parent, name, index, DEFAULT_COLUMN_WIDTH);
	}

	/**
	 * Create a table column with the image and the width of the column is set
	 * to the image width.
	 * 
	 * @param parent
	 *            the table that contains this column
	 * @param image
	 *            image for this column
	 * @return the new table column
	 */
	public static TableColumn createTableColumn(Table parent, Image image,
			int index) {
		return createTableColumn(parent, image, index, 2);
	}

	/**
	 * Create a table column with the image and the width of the column is set
	 * to the image width.
	 * 
	 * @param parent
	 *            the table that contains this column
	 * @param image
	 *            image for this column
	 * @param index
	 *            the index column number for the image.
	 * @param imageIncrease
	 *            increase the size of the spacing in the column
	 * @return the new table column
	 */
	public static TableColumn createTableColumn(Table parent, Image image,
			int index, int imageIncrease) {
		TableColumn column = new TableColumn(parent, SWT.LEFT, index);
		column.setImage(image);
		column.setWidth(image.getBounds().width + imageIncrease);
		column.setResizable(false);
		return column;
	}

	/**
	 * Create a table column
	 * 
	 * @param parent
	 *            the table that contains this column
	 * @param name
	 *            name of this column
	 * @param index
	 *            the column within the parent composite
	 * @param columnWidth
	 *            the width for the column
	 * @return the new table column
	 */
	public static TableColumn createTableColumn(Table parent, String name,
			int index, int columnWidth) {
		TableColumn column = new TableColumn(parent, SWT.LEFT, index);
		column.setText(name);
		column.setWidth(columnWidth);
		return column;
	}

	/**
	 * Create a text field
	 * 
	 * @param parent
	 *            the parent of the new text field
	 * @return the new text field
	 */
	public static Text createTextBox(Composite parent) {
		return createTextBox(parent, 1, DEFAULT_TEXTBOX_WIDTH);
	}

	/**
	 * Create a text field
	 * 
	 * @param parent
	 *            the parent of the new text field
	 * @param text
	 *            the initial value of the text field
	 * @return the new text field
	 */
	public static Text createTextBox(Composite parent, String text) {
		Text textbox = createTextBox(parent, 1);
		textbox.setText(text);
		return textbox;
	}

	/**
	 * Create a text field
	 * 
	 * @param parent
	 *            the parent of the new text field
	 * @param hSpan
	 *            number of columns the text box is to occupy
	 * @return the new text field
	 */
	public static Text createTextBox(Composite parent, int hSpan) {
		return createTextBox(parent, hSpan, DEFAULT_TEXTBOX_WIDTH);
	}

	/**
	 * Create a text field
	 * 
	 * @param parent
	 *            the parent of the new text field
	 * @param hSpan
	 *            number of columns the text box is to occupy
	 * @param minWidth
	 *            minimum width of text field
	 * @return the new text field
	 */
	public static Text createTextBox(Composite parent, int hSpan, int minWidth) {
		return createTextBox(parent, hSpan, minWidth, -1);
	}

	/**
	 * Create a text field
	 * 
	 * @param parent
	 *            the parent of the new text field
	 * @param hSpan
	 *            number of columns the text box is to occupy
	 * @param minWidth
	 *            minimum width of text field. Pass -1 to use default.
	 * @param minHeight
	 *            minimum height of text field. Pass -1 to use default.
	 * @return the new text field
	 */
	public static Text createTextBox(Composite parent, int hSpan, int minWidth,
			int minHeight) {
		return createTextBox(parent, hSpan, minWidth, minHeight, false);
	}

	/**
	 * Create a text field
	 * 
	 * @param parent
	 *            the parent of the new text field
	 * @param hSpan
	 *            number of columns the text box is to occupy
	 * @param minWidth
	 *            minimum width of text field. Pass -1 to use default.
	 * @param minHeight
	 *            minimum height of text field. Pass -1 to use default.
	 * @param bFill
	 *            True to make the textbox occupies the horizontal space. False
	 *            otherwise.
	 * @return the new text field
	 */
	public static Text createTextBox(Composite parent, int hSpan, int minWidth,
			int minHeight, boolean bFill) {
		Text text = new Text(parent, SWT.SINGLE | SWT.BORDER);
		GridData data = new GridData(bFill ? GridData.FILL_HORIZONTAL
				: GridData.FILL);
		if (hSpan < 0) {
			data.horizontalSpan = 1;
		} else {
			data.horizontalSpan = hSpan;
		}
		if (minWidth > 0) {
			data.widthHint = minWidth;
		}
		if (minHeight > 0) {
			data.heightHint = minHeight;
		}
		text.setLayoutData(data);
		return text;
	}

	/**
	 * Create a styled text field
	 * 
	 * @param parent
	 *            the parent of the new styled text field
	 * @param hSpan
	 *            number of columns the styled text box is to occupy
	 * @param minWidth
	 *            minimum width of styled text field. Pass -1 to use default.
	 * @param minHeight
	 *            minimum height of styled text field. Pass -1 to use default.
	 * @param bFill
	 *            True to make the styled textbox occupies the horizontal space.
	 *            False otherwise.
	 * @return the new styled text field
	 */
	public static StyledText createStyledTextBox(Composite parent, int hSpan,
			int minWidth, int minHeight, boolean bFill) {
		StyledText styledText = new StyledText(parent, SWT.SINGLE | SWT.BORDER);
		GridData data = new GridData(bFill ? GridData.FILL_HORIZONTAL
				: GridData.FILL);
		if (hSpan < 0) {
			data.horizontalSpan = 1;
		} else {
			data.horizontalSpan = hSpan;
		}
		if (minWidth > 0) {
			data.widthHint = minWidth;
		}
		if (minHeight > 0) {
			data.heightHint = minHeight;
		}
		styledText.setLayoutData(data);
		return styledText;
	}

	/**
	 * Create a text field that is scroll-able in vertical direction. This is
	 * normally the only direction desired.
	 * 
	 * @param parent
	 *            the parent of the new text field
	 * @param hSpan
	 *            number of columns the text box is to occupy
	 * @param minWidth
	 *            minimum width of text field
	 * @param minHeight
	 *            minimum height of text field
	 * @return the new text field
	 */
	public static Text createTextBoxScrollable(Composite parent, int hSpan,
			int minWidth, int minHeight) {
		Text text = new Text(parent, SWT.BORDER | SWT.V_SCROLL | SWT.WRAP);
		GridData data = new GridData((minWidth > 0) ? GridData.FILL
				: GridData.FILL_HORIZONTAL);
		data.horizontalSpan = hSpan;
		if (minWidth > 0) {
			data.widthHint = minWidth;
		}
		data.heightHint = minHeight;

		text.setLayoutData(data);
		return text;
	}

	/**
	 * Create a text field that is scroll-able in both vertical and horizontal
	 * directions.
	 * 
	 * @param parent
	 *            the parent of the new text field
	 * @param hSpan
	 *            number of columns the text box is to occupy
	 * @param minWidth
	 *            minimum width of text field
	 * @param minHeight
	 *            minimum height of text field
	 * @return the new text field
	 */
	public static Text createTextBoxAllScrollable(Composite parent, int hSpan,
			int minWidth, int minHeight) {
		return createTextBoxAllScrollable(parent, hSpan, minWidth, minHeight,
				(minWidth > 0));
	}

	/**
	 * Create a text field that is scroll-able in both vertical and horizontal
	 * directions.
	 * 
	 * @param parent
	 *            the parent of the new text field
	 * @param hSpan
	 *            number of columns the text box is to occupy
	 * @param minWidth
	 *            minimum width of text field
	 * @param minHeight
	 *            minimum height of text field
	 * @param bFill
	 *            should the pattern be fill or fill horizontal.
	 * @return the new text field
	 */
	public static Text createTextBoxAllScrollable(Composite parent, int hSpan,
			int minWidth, int minHeight, boolean bFill) {
		Text text = new Text(parent, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
		GridData data = new GridData(bFill ? GridData.FILL
				: GridData.FILL_HORIZONTAL);
		data.horizontalSpan = hSpan;
		if (minWidth > 0) {
			data.widthHint = minWidth;
		}
		data.heightHint = minHeight;

		text.setLayoutData(data);
		return text;
	}

	/**
	 * Create a list with the items listed in it.
	 * 
	 * @param parent
	 *            the parent of the new text field
	 * @param numColumns
	 *            number of columns the text box is to occupy
	 * @param minWidth
	 *            minimum width of text field
	 * @param minHeight
	 *            minimum height of text field
	 * @param items
	 *            the items in the list
	 * @return the new list
	 */
	public static List createList(Composite parent, int numColumns,
			int minWidth, int minHeight, String[] items) {
		return createList(parent, numColumns, minWidth, minHeight, items, true);
	}

	/**
	 * Create a list with the items listed in it.
	 * 
	 * @param parent
	 *            the parent of the new list box
	 * @param hSpan
	 *            number of columns the list box is to occupy
	 * @param minWidth
	 *            minimum width of list box
	 * @param minHeight
	 *            minimum height of list box
	 * @param items
	 *            the items in the list
	 * @param bmulti
	 *            whether multiple item selection is allowed
	 * @param verticalSpan
	 *            the number of rows the list box is to occupy
	 * @return the new list
	 */
	public static List createList(Composite parent, int hSpan, int minWidth,
			int minHeight, String[] items, boolean bmulti) {
		return createList(parent, hSpan, minWidth, minHeight, items, bmulti, 1);
	}

	/**
	 * Create a list with the items listed in it.
	 * 
	 * @param parent
	 *            the parent of the new list box
	 * @param hSpan
	 *            number of columns the list box is to occupy
	 * @param minWidth
	 *            minimum width of list box
	 * @param minHeight
	 *            minimum height of list box
	 * @param items
	 *            the items in the list
	 * @param bmulti
	 *            whether multiple item selection is allowed
	 * @param vSpan
	 *            the number of rows the list box is to occupy
	 * @return the new list
	 */
	public static List createList(Composite parent, int hSpan, int minWidth,
			int minHeight, String[] items, boolean bmulti, int vSpan) {
		return createList(parent, hSpan, minWidth, minHeight, items, bmulti,
				vSpan, GridData.VERTICAL_ALIGN_BEGINNING
						| GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
	}

	/**
	 * Create a list with the items listed in it.
	 * 
	 * @param parent
	 *            the parent of the new list box
	 * @param hSpan
	 *            number of columns the list box is to occupy
	 * @param minWidth
	 *            minimum width of list box
	 * @param minHeight
	 *            minimum height of list box
	 * @param items
	 *            the items in the list
	 * @param bmulti
	 *            whether multiple item selection is allowed
	 * @param vSpan
	 *            the number of rows the list box is to occupy
	 * @param style
	 *            Style of GridData (eg. GridData.FILL_BOTH)
	 * @return the new list
	 */
	public static List createList(Composite parent, int hSpan, int minWidth,
			int minHeight, String[] items, boolean bmulti, int vSpan, int style) {
		return createList(parent, hSpan, minWidth, minHeight, items, bmulti,
				false, vSpan, style);
	}

	/**
	 * Create a list with the items listed in it.
	 * 
	 * @param parent
	 *            the parent of the new list box
	 * @param hSpan
	 *            number of columns the list box is to occupy
	 * @param minWidth
	 *            minimum width of list box
	 * @param minHeight
	 *            minimum height of list box
	 * @param items
	 *            the items in the list
	 * @param bmulti
	 *            whether multiple item selection is allowed
	 * @param bCheck
	 *            true for a check box list
	 * @param vSpan
	 *            the number of rows the list box is to occupy
	 * @param style
	 *            Style of GridData (eg. GridData.FILL_BOTH)
	 * @return the new list
	 */
	public static List createList(Composite parent, int hSpan, int minWidth,
			int minHeight, String[] items, boolean bMulti, boolean bCheck,
			int vSpan, int style) {
		int listStyle = SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER;
		listStyle = listStyle | (bMulti ? SWT.MULTI : SWT.SINGLE);
		if (bCheck)
			listStyle = listStyle | SWT.CHECK;

		List theList = new List(parent, listStyle);
		GridData data = new GridData(style);
		data.horizontalSpan = hSpan;
		if (minWidth > -1) {
			data.widthHint = minWidth;
		}
		if (minHeight > -1) {
			data.heightHint = minHeight;
		}
		data.verticalSpan = vSpan;
		theList.setLayoutData(data);
		if (items != null) {
			theList.setItems(items);
		}

		return theList;
	}

	/**
	 * Computes the size of the composite inside the scroll area so that scroll
	 * bars show up correctly.
	 * 
	 * @param parentComposite
	 * @param childComposite
	 */
	public static void computeScrollArea(ScrolledComposite parentComposite,
			Composite childComposite) {
		// Point pt = childComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
		// childComposite.setSize(pt);

		Point pt = childComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
		parentComposite.setExpandHorizontal(true);
		parentComposite.setExpandVertical(true);
		if (System.getProperties().getProperty("os.name").equalsIgnoreCase(
				"linux"))
		// On Linux platform the inner html window of the browser window is only
		// 66x66 in siye and won't change
		// If the min-size is larger than the outer composite, after re-sizing
		// the outer composite, the size
		// of the inner gets adjusted....weird....but at least a workaround
		{
			parentComposite.setMinWidth(pt.x * 5);
			parentComposite.setMinHeight(pt.y * 5);
		} else {
			parentComposite.setMinWidth(pt.x);
			parentComposite.setMinHeight(pt.y);
		}
	}

	/**
	 * Builds an array of strings from a token list string. The token separator
	 * is a comma (',').
	 * 
	 * @param tokenString
	 * @return String[]
	 */
	public static String[] getTokenNames(String tokenString) {
		if ((tokenString == null) || (tokenString.length() == 0)) {
			return new String[0];
		}

		return tokenString.split(",");
	}

	/**
	 * Builds an string from a token list. The token separator is a comma (',').
	 * 
	 * @param String
	 *            [] tokens
	 * @return tokenString
	 */
	public static String getTokenString(String[] tokens) {
		if ((tokens == null) || (tokens.length == 0)) {
			return "";
		}
		StringBuffer sb = new StringBuffer();
		for (int ii = 0; ii < tokens.length; ii++) {
			sb.append(tokens[ii]);
			if (ii < tokens.length - 1) {
				sb.append(",");
			}
		}
		return sb.toString();
	}

	/**
	 * Builds an array of int from a token list string. The token separator is a
	 * comma (',').
	 * 
	 * @param tokenString
	 * @return int[]
	 */
	public static int[] getTokenIndexes(String tokenString) {
		String[] tokens = getTokenNames(tokenString);
		int[] iTokens = new int[tokens.length];

		for (int ii = 0; ii < tokens.length; ii++) {
			iTokens[ii] = Integer.parseInt(tokens[ii]);
		}
		return iTokens;
	}

	/**
	 * Builds an string from a token list. The token separator is a comma (',').
	 * 
	 * @param int[] tokens
	 * @return tokenString
	 */
	public static String getTokenString(int[] tokens) {
		if ((tokens == null) || (tokens.length == 0)) {
			return "";
		}
		StringBuffer sb = new StringBuffer();
		for (int ii = 0; ii < tokens.length; ii++) {
			sb.append(tokens[ii]);
			if (ii < tokens.length - 1) {
				sb.append(",");
			}
		}
		return sb.toString();
	}

	/**
	 * Enable/Disable the widget and all its children.
	 * 
	 * @param widget
	 *            The widget to be enabled/disabled.
	 * @param state
	 *            Enable widget if true. Disable otherwise.
	 */
	public static void setWidgetState(Control widget, boolean state) {
		if (widget instanceof Composite) {
			Control widgets[] = ((Composite) widget).getChildren();
			for (int i = 0; i < widgets.length; i++) {
				setWidgetState(widgets[i], state);
			}
		}
		widget.setEnabled(state);
	}

	/**
	 * Move the selected item up in the table.
	 * 
	 * @param table
	 *            The table of which items are moved up.
	 */
	public static void tableMoveUp(Table table) {
		tableMoveUp(table, null);
	}

	/**
	 * Move the selected item up in the table.
	 * 
	 * @param table
	 *            The table of which items are moved up.
	 */
	public static void tableMoveUp(Table table, String[] dataKeys) {
		int selectedIndex = table.getSelectionIndex();

		// If nothing is selected or the item is already at the top,
		// do nothing.
		if (selectedIndex <= 0) {
			return;
		}

		// Remember properties of the selected Item (text, checked, image, data)
		TableItem selectedItem = table.getItem(selectedIndex);
		boolean selectedItemChecked = selectedItem.getChecked();
		boolean selectedItemGrayed = selectedItem.getGrayed();
		int columnCount = table.getColumnCount();
		String[] selectedItemValues = new String[columnCount];
		Image[] selectedItemImage = new Image[columnCount];
		for (int i = 0; i < columnCount; i++) {
			// Remember the values of this item
			selectedItemValues[i] = selectedItem.getText(i);
			selectedItemImage[i] = selectedItem.getImage(i);
		}
		Object[] selectedItemData = null;
		if (dataKeys != null) {
			selectedItemData = new Object[dataKeys.length + 1];
			for (int i = 0; i < dataKeys.length; i++) {
				selectedItemData[i] = selectedItem.getData(dataKeys[i]);
			}
			selectedItemData[dataKeys.length] = selectedItem.getData();
		}

		// Copy values of item above to selected item
		TableItem aboveItem = table.getItem(selectedIndex - 1);
		selectedItem.setChecked(aboveItem.getChecked());
		selectedItem.setGrayed(aboveItem.getGrayed());
		for (int i = 0; i < columnCount; i++) {
			selectedItem.setText(i, aboveItem.getText(i));
			Image aboveItemImage = aboveItem.getImage(i);
			if (aboveItemImage != null) {
				selectedItem.setImage(i, aboveItemImage);
			}
		}
		if (dataKeys != null && selectedItemData != null) {
			for (int i = 0; i < dataKeys.length; i++) {
				selectedItem.setData(dataKeys[i], aboveItem
						.getData(dataKeys[i]));
			}
			selectedItem.setData(aboveItem.getData());
		}

		// Copy values of saved values to item above
		aboveItem.setChecked(selectedItemChecked);
		aboveItem.setGrayed(selectedItemGrayed);
		for (int i = 0; i < columnCount; i++) {
			aboveItem.setText(i, selectedItemValues[i]);
			if (selectedItemImage[i] != null) {
				aboveItem.setImage(i, selectedItemImage[i]);
			}
		}
		if (dataKeys != null && selectedItemData != null) {
			for (int i = 0; i < dataKeys.length; i++) {
				aboveItem.setData(dataKeys[i], selectedItemData[i]);
			}
			aboveItem.setData(selectedItemData[dataKeys.length]);
		}

		table.select(selectedIndex - 1);
		table.showSelection();
	}

	/**
	 * Move the selected item down in the table.
	 * 
	 * @param table
	 *            The table of which items are moved.
	 */
	public static void tableMoveDown(Table table) {
		tableMoveDown(table, null);
	}

	/**
	 * Move the selected item down in the table.
	 * 
	 * @param table
	 *            The table of which items are moved.
	 */
	public static void tableMoveDown(Table table, String[] dataKeys) {
		int selectedIndex = table.getSelectionIndex();

		// If nothing is selected or the item is already at the bottom,
		// do nothing.
		if (selectedIndex < 0 || selectedIndex == table.getItemCount() - 1) {
			return;
		}

		// Remember the values of the selected item
		TableItem selectedItem = table.getItem(selectedIndex);
		boolean selectedItemChecked = selectedItem.getChecked();
		boolean selectedItemGrayed = selectedItem.getGrayed();
		int columnCount = table.getColumnCount();
		String[] selectedItemValues = new String[columnCount];
		Image[] selectedItemImage = new Image[columnCount];
		for (int i = 0; i < columnCount; i++) {
			selectedItemValues[i] = selectedItem.getText(i);
			selectedItemImage[i] = selectedItem.getImage(i);
		}
		Object[] selectedItemData = null;
		if (dataKeys != null) {
			selectedItemData = new Object[dataKeys.length + 1];
			for (int j = 0; j < dataKeys.length; j++) {
				selectedItemData[j] = selectedItem.getData(dataKeys[j]);
			}
			selectedItemData[dataKeys.length] = selectedItem.getData();
		}

		// Copy the values from the item below to the selected index
		TableItem belowItem = table.getItem(selectedIndex + 1);
		selectedItem.setChecked(belowItem.getChecked());
		selectedItem.setGrayed(belowItem.getGrayed());
		for (int i = 0; i < columnCount; i++) {
			selectedItem.setText(i, belowItem.getText(i));
			Image belowItemImage = belowItem.getImage(i);
			if (belowItemImage != null) {
				selectedItem.setImage(i, belowItemImage);
			}
		}
		if (dataKeys != null && selectedItemData != null) {
			for (int i = 0; i < dataKeys.length; i++) {
				selectedItem.setData(dataKeys[i], belowItem
						.getData(dataKeys[i]));
			}
			selectedItem.setData(belowItem.getData());
		}

		// Copy the saved values to the item below
		belowItem.setChecked(selectedItemChecked);
		belowItem.setGrayed(selectedItemGrayed);
		for (int i = 0; i < columnCount; i++) {
			belowItem.setText(i, selectedItemValues[i]);
			if (selectedItemImage[i] != null) {
				belowItem.setImage(i, selectedItemImage[i]);
			}
		}
		if (dataKeys != null && selectedItemData != null) {
			for (int i = 0; i < dataKeys.length; i++) {
				belowItem.setData(dataKeys[i], selectedItemData[i]);
			}
			belowItem.setData(selectedItemData[dataKeys.length]);
		}

		table.select(selectedIndex + 1);
		table.showSelection();
	}

	// //////////////////////////////////////////////////////////////////////////////////////////
	// Tree based methods
	// //////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * Add columns to a Tree object
	 * 
	 * @param tree
	 *            the Tree these columns should be added to.
	 * @param columns
	 *            A string array containing names of the columns in the order
	 *            that they should be displayed in the tree.
	 * @return the new table
	 */
	public static void setTreeColumns(Tree tree, String[] columns) {
		createTreeColumns(tree, columns, DEFAULT_COLUMN_WIDTH);
	}

	/**
	 * Add columns to a Tree object
	 * 
	 * @param tree
	 *            the Tree these columns should be added to.
	 * @param columns
	 *            A string array containing names of the columns in the order
	 *            that they should be displayed in the tree.
	 * @param columnWidth
	 *            width of the column in the tree.
	 */
	public static void createTreeColumns(Tree tree, String[] columns,
			int columnWidth) {
		if (columns != null) {
			for (int i = 0; i < columns.length; i++) {
				createTreeColumn(tree, columns[i], i, columnWidth);
			}
		}
	}

	/**
	 * Create a Tree column
	 * 
	 * @param tree
	 *            the tree that contains this column
	 * @param name
	 *            name of this column
	 * @param index
	 *            the column within the parent composite
	 * @return the new tree column
	 */
	public static TreeColumn createTreeColumn(Tree tree, String name, int index) {
		return createTreeColumn(tree, name, index, DEFAULT_COLUMN_WIDTH);
	}

	/**
	 * Create a Tree column
	 * 
	 * @param tree
	 *            the tree that contains this column
	 * @param name
	 *            name of this column
	 * @param index
	 *            the column within the parent composite
	 * @param columnWidth
	 *            the width for the column
	 * @return the new tree column
	 */
	public static TreeColumn createTreeColumn(Tree tree, String name,
			int index, int columnWidth) {
		TreeColumn column = new TreeColumn(tree, SWT.LEFT, index);
		column.setText(name);
		column.setWidth(columnWidth);
		return column;
	}

	/**
	 * Create a Tree object
	 * 
	 * @param parent
	 *            the composite that contains the Tree
	 * @return the new Tree object
	 */
	public static Tree createTree(Composite parent) {
		return createTree(parent, -1);
	}

	/**
	 * Create a Tree object
	 * 
	 * @param parent
	 *            the composite that contains the Tree
	 * @return the new Tree object
	 */
	public static Tree createTree(Composite parent, boolean bMulti) {
		int style = (bMulti ? SWT.MULTI : SWT.SINGLE) | SWT.BORDER
				| SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION
				| SWT.HIDE_SELECTION;
		return createTree(parent, style);
	}

	/**
	 * Create a Tree object
	 * 
	 * @param parent
	 *            the composite that contains the Tree
	 * @param style
	 *            Style of the Tree. Use "-1" for the default style which is
	 *            SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL |
	 *            SWT.FULL_SELECTION | SWT.HIDE_SELECTION
	 * @return the new Tree object
	 */
	public static Tree createTree(Composite parent, int style) {
		return createTree(parent, style, DEFAULT_TREE_HEIGHT_WIDTH,
				DEFAULT_TREE_HEIGHT_WIDTH, 1, 1, true);
	}

	/**
	 * Creates a Tree object.
	 * 
	 * @param parent
	 *            The composite that contains the Tree
	 * @param style
	 *            Style of the Tree. Use "-1" for the default style which is
	 *            SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL |
	 *            SWT.FULL_SELECTION | SWT.HIDE_SELECTION
	 * @param treeWidth
	 *            the minimum width for the tree
	 * @param treeHeight
	 *            the minimum height for the tree
	 * @param horizontalSpan
	 *            Number of columns the Tree is to occupy.
	 * @param verticalSpan
	 *            Number of rows the Tree is to occupy.
	 * @param bHasColumns
	 *            set true and the Tree will be setup with visible lines.
	 * @return The new Tree object.
	 */
	public static Tree createTree(Composite parent, int style, int treeWidth,
			int treeHeight, int horizontalSpan, int verticalSpan,
			boolean bHasColumns) {
		int realStyle = style;
		if (realStyle == -1) {
			// SINGLE, MULTI, CHECK, FULL_SELECTION
			realStyle = SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL
					| SWT.FULL_SELECTION | SWT.HIDE_SELECTION;
		}

		Tree theTree = new Tree(parent, realStyle);
		GridData gridData = new GridData(GridData.FILL_BOTH);
		gridData.grabExcessVerticalSpace = true;
		gridData.grabExcessHorizontalSpace = true;
		gridData.verticalSpan = verticalSpan;
		gridData.horizontalSpan = horizontalSpan;
		if (treeWidth > 0) {
			gridData.widthHint = treeWidth;
		}
		if (treeHeight > 0) {
			gridData.heightHint = treeHeight;
		}
		theTree.setLayoutData(gridData);

		if (bHasColumns) {
			theTree.setHeaderVisible(true);
			theTree.setLinesVisible(true);
		}
		return theTree;
	}

	/**
	 * Create a TreeEditor object
	 * 
	 * @param theTree
	 *            the Tree that this editor is for
	 * @return the new TreeEditor object
	 */
	public static TreeEditor createTreeEditor(Tree theTree) {
		TreeEditor editor = new TreeEditor(theTree);
		editor.horizontalAlignment = SWT.LEFT;
		editor.grabHorizontal = true;
		editor.minimumWidth = DEFAULT_COLUMN_WIDTH;
		return editor;
	}

	/**
	 * Expands or collapse all nodes of a tree.
	 * 
	 * @param tree
	 *            The tree of which nodes are expanded or collapsed.
	 * @param expand
	 *            true for expand all, false for collapse all
	 */
	public static void expandOrCollapseAll(Tree tree, boolean expand) {
		TreeItem[] items = tree.getItems();
		for (int i = 0; i < items.length; i++) {
			expandOrCollapseAll(items[i], expand);
			items[i].setExpanded(expand);
		}
	}

	/**
	 * Expands or collapse all nodes of a TreeItem.
	 * 
	 * @param item
	 *            The tree item of which all nodes are expanded or collapsed.
	 * @param expand
	 *            true for expand all, false for collapse all
	 */
	public static void expandOrCollapseAll(TreeItem item, boolean expand) {
		if (item.getItemCount() > 0) {
			TreeItem[] children = item.getItems();
			for (int i = 0; i < children.length; i++) {
				expandOrCollapseAll(children[i], expand);
				children[i].setExpanded(expand);
			}
		}
	}

	/**
	 * Create a spinner control. It will spin between the min and max int
	 * values.
	 * 
	 * @param parent
	 *            composite to add the item with a single spacing value to.
	 * @param maxValue
	 *            maximum value the spinner goes to.
	 * @param minValue
	 *            minimum value the spinner goes to.
	 * @param bReadOnly
	 *            true if you want the control edit part to read only so it can
	 *            only be set via the spinners.
	 * @return the created spinner.
	 */
	public static Spinner createSpinner(Composite parent, int maxValue,
			int minValue, boolean bReadOnly) {
		int style = SWT.BORDER;
		if (bReadOnly) {
			style |= SWT.READ_ONLY;
		}

		Spinner spin = new Spinner(parent, style);
		spin.setMaximum(maxValue);
		spin.setMinimum(minValue);

		return spin;
	}

	/**
	 * Create a table header from a Composite object. This is a real table but
	 * only the header is designed to be shown.
	 * 
	 * @param composite
	 *            the Composite this table is to be created from
	 * @param tableWidth
	 *            the minimum width for the table.
	 * @param horizontalSpan
	 *            the number of columns the table is to occupy.
	 * @return the new table
	 */
	public static Table createTableHeader(Composite composite, int tableWidth,
			int horizontalSpan) {
		// SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION
		int style = SWT.NONE;

		Table table = new Table(composite, style);
		GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
		gridData.horizontalSpan = horizontalSpan;
		if (tableWidth > 0) {
			gridData.widthHint = tableWidth;
		}
		gridData.heightHint = 0;
		table.setLayoutData(gridData);
		table.setHeaderVisible(true);
		table.setLinesVisible(true);

		return table;
	}

}
